# -*- coding: utf-8 -*-

"""
  @author: tangliqi
  @date: 2022/12/26 11:43
  @python version: 3.6 
  @contact me: 110
  ---------------------------------------
  @desc: python设计模式实现 => 状态模式.py
"""
from abc import abstractmethod
from enum import Enum


# 通过一个工作流审批的例子来说明
# 在A公司的工作流审批中，会有小组审批、部门审批，审批拒绝、审批成功这些状态
# 每个状态定义了各自转移到其它状态时触发的事件及对应的行为
# 状态模式的构成： 1.状态基类 2.状态子类（继承自状态基类）3.流程调用类，用于维护当前状态


# ============================  状态基类  ============================
class State:
    Allow = []

    def __init__(self):
        self.load_event()

    def switch(self, to):
        """"""
        state = to.get_current_state()

        assert state in self.Allow, "不被允许的状态转移 {} => {}".format(self.__class__.__name__,
                                                                to.__class__.__name__)
        self._event[state]()

    # 事件
    @abstractmethod
    def load_event(self):
        """子类规定自己的事件和动作"""
        pass

    def _to_department(self):
        raise Exception("不允许前往部门审批流程")

    def _to_success(self):
        raise Exception("不允许前往成功审批流程")

    def _to_refuse(self):
        raise Exception("不允许拒绝审批流程")

    def _to_group(self):
        raise Exception("不允许前往小组审批流程")

    @abstractmethod
    def get_current_state(self):
        """获取当前状态"""
        pass


# ============================  状态子类  ============================
class Status(Enum):
    group = "group"
    department = "department"
    success = "success"
    refuse = "refuse"


# 小组状态
class GroupState(State):
    Allow = [
        Status.department.value,
        Status.refuse.value
    ]

    def load_event(self):
        self._event = {
            Status.department.value: self._to_department,
            Status.refuse.value: self._to_refuse
        }

    def _to_department(self):
        print("审批通过，流程到了department。")

    def _to_refuse(self):
        print("审批拒绝，流程被拒绝。")

    def get_current_state(self):
        return Status.group.value


# 部门状态
class DepartmentState(State):
    Allow = [
        Status.group.value,
        Status.refuse.value,
        Status.success.value
    ]

    def load_event(self):
        self._event = {
            Status.group.value: self._to_group,
            Status.success.value: self._to_success,
            Status.refuse.value: self._to_refuse
        }

    def _to_group(self):
        print("审批通过，流程到了group。")

    def _to_refuse(self):
        print("审批拒绝，流程被拒绝。")

    def _to_success(self):
        print("审批通过，流程执行成功。")

    def get_current_state(self):
        return Status.department.value


# 成功状态
class SuccessState(State):
    Allow = []

    def load_event(self):
        pass

    def get_current_state(self):
        return Status.success.value


# 拒绝状态
class RefuseState(State):
    Allow = []

    def load_event(self):
        pass

    def get_current_state(self):
        return Status.refuse.value


# ============================  mixin方式重组状态类  ============================
# 当事件与事件触发的动作对于不同的状态来说，都相同或比较相似时，可以采用mixin组合的方式将事件单独拆分出来。
# 根据这个思路，对上面的抽象状态类和状态子类进行重组

# ============== #
#    抽象状态基类
# ============== #
class StateNew:
    Allow = []

    def __init__(self):
        self.load_event()

    def switch(self, to):
        """"""
        state = to.get_current_state()

        assert state in self.Allow, "不被允许的状态转移 {} => {}".format(self.__class__.__name__,
                                                                to.__class__.__name__)
        self._event[state]()

    @abstractmethod
    def get_current_state(self):
        """获取当前状态"""
        pass

    # 事件
    @abstractmethod
    def load_event(self):
        """子类规定自己的事件和动作"""
        pass


# ============== #
#    mixin
# ============== #
class ToGroup:
    def _to_group(self):
        print("审批通过，流程到了group。")


class ToDepartment:
    def _to_department(self):
        print("审批通过，流程到了department。")


class ToSuccess:
    def _to_success(self):
        print("审批通过，流程执行成功。")


class ToRefuse:
    def _to_refuse(self):
        print("审批拒绝，流程被拒绝。")


# ============== #
#    状态子类
# ============== #
class GroupStateNew(ToDepartment, ToRefuse, StateNew):
    Allow = [
        Status.department.value,
        Status.refuse.value
    ]

    def load_event(self):
        self._event = {
            Status.department.value: self._to_department,
            Status.refuse.value: self._to_refuse
        }

    def get_current_state(self):
        return Status.group.value


class DepartmentStateNew(ToGroup, ToRefuse, ToSuccess, StateNew):
    Allow = [
        Status.group.value,
        Status.refuse.value,
        Status.success.value
    ]

    def load_event(self):
        self._event = {
            Status.group.value: self._to_group,
            Status.success.value: self._to_success,
            Status.refuse.value: self._to_refuse
        }

    def get_current_state(self):
        return Status.department.value


class SuccessStateNew(StateNew):

    def get_current_state(self):
        return Status.success.value

    def load_event(self):
        pass


class RefuseStateNew(StateNew):

    def get_current_state(self):
        return Status.refuse.value

    def load_event(self):
        pass


# ============================  流程调用类  ============================
class Flow:
    def __init__(self, state):
        self.current_state = state
        self.state_chain = [state]
        self.flow_str = state.get_current_state() + " ---> "

    def run(self, to):
        self.current_state.switch(to)

        self.current_state = to
        self.state_chain.append(to)

        self.add_flow(to)

    def add_flow(self, to):
        self.flow_str += (to.get_current_state() + " ---> ")

    def get_flow(self):
        print(self.flow_str)

    def end(self):
        self.flow_str += "end"


if __name__ == '__main__':
    # group = GroupState()
    # department = DepartmentState()
    # success = SuccessState()

    group = GroupStateNew()
    department = DepartmentStateNew()
    success = SuccessStateNew()

    # 创建一个流程，从小组开始
    flow = Flow(group)
    flow.get_flow()

    # 流转到部门
    flow.run(department)
    flow.get_flow()
    print(flow.current_state)

    # 流转到成功
    flow.run(success)
    # 结束审批流程
    flow.end()
    flow.get_flow()
